<template>
  <div class="d-flex-row" id="divId">
    <el-form v-bind="getFormProp(formData)" ref="xmform" class="form-item">
      <template v-for="(value, name, index) in formData.model">
        <el-form-item
          class="item"
          :key="name"
          :label="formData.props[name].label"
          :prop="name"
          v-if="index > columnNum ? showSearchAll : true"
        >
          <!-- input类型 -->
          <el-input
            :style="{ width: inputWidth + 'px' }"
            v-if="formData.props[name].type === 'text'"
            v-model="formData.model[name]"
            v-bind="formData.props[name]"
            v-on="formData.methods[name]"
            :maxlength="
              formData.props[name].maxlength
                ? formData.props[name].maxlength
                : '128'
            "
          >
            <template
              v-for="slotName in formData.props[name].slotName"
              :slot="slotName"
            >
              <div :key="slotName">
                <slot :name="name + '-' + slotName"></slot>
              </div>
            </template>
          </el-input>
          <!-- number类型 -->
          <el-input
            v-if="formData.props[name].type === 'number'"
            v-model="formData.model[name]"
            v-bind="getItemProps(name)"
            v-on="formData.methods[name]"
            :style="{ width: inputWidth + 'px' }"
            @input="
              value =>
                mergeInputNumberFun(name, value, formData.props[name].precision)
            "
            @change="value => mergeChangeNumberFun(name, value)"
          ></el-input>

          <!-- inputNumber类型 -->
          <el-input-number
            v-if="formData.props[name].type === 'input-number'"
            v-model="formData.model[name]"
            v-bind="formData.props[name]"
            v-on="formData.methods[name]"
            :style="{ width: inputWidth + 'px' }"
          ></el-input-number>

          <!-- date-picker -->
          <el-date-picker
            v-if="isDateType(formData.props[name].type)"
            v-model="formData.model[name]"
            v-bind="formData.props[name]"
            v-on="formData.methods[name]"
            :picker-options="formData.props[name].pickerOptions"
            :style="{ width: inputWidth + 'px' }"
          >
          </el-date-picker>
          <!-- time-picker -->
          <el-time-picker
            v-if="formData.props[name].type === 'time'"
            v-model="formData.model[name]"
            v-bind="formData.props[name]"
            v-on="formData.methods[name]"
            :style="{ width: inputWidth + 'px' }"
          >
          </el-time-picker>
          <!-- select类型 -->
          <el-select
            v-if="formData.props[name].type === 'select'"
            v-model="formData.model[name]"
            v-bind="formData.props[name]"
            v-on="formData.methods[name]"
            :style="{ width: inputWidth + 'px' }"
          >
            <el-option
              v-for="option in formData.props[name].options"
              :key="option.value"
              :label="option.label"
              :value="option.value"
              :disabled="option.disabled"
            ></el-option>
          </el-select>
          <!-- treeselect -->
          <treeselect
            :style="{ width: inputWidth + 'px' }"
            :class="classSize"
            v-if="formData.props[name].type === 'tree-select'"
            v-model="formData.model[name]"
            v-bind="formData.props[name]"
            v-on="formData.methods[name]"
          >
            <template
              :slot="slotName"
              slot-scope="{
                node,
                shouldShowCount,
                count,
                labelClassName,
                countClassName
              }"
              v-for="slotName in formData.props[name].slotName"
            >
              <div :key="slotName">
                <template v-if="slotName == 'option-label'">
                  <slot
                    :name="name + '-' + slotName"
                    :node="node"
                    :shouldShowCount="shouldShowCount"
                    :count="count"
                    :labelClassName="labelClassName"
                    :countClassName="countClassName"
                  ></slot>
                </template>
                <template v-if="slotName == 'value-label'">
                  <slot :name="name + '-' + slotName" :node="node"></slot>
                </template>

                <template
                  v-if="slotName == 'before-list' || slotName == 'after-list'"
                >
                  <slot :name="name + '-' + slotName"></slot>
                </template>
              </div>
            </template>
          </treeselect>
          <!-- switch -->
          <el-switch
            :style="{ width: inputWidth + 'px' }"
            v-if="formData.props[name].type === 'switch'"
            v-model="formData.model[name]"
            v-bind="formData.props[name]"
            v-on="formData.methods[name]"
          ></el-switch>
          <!-- radio -->
          <el-radio-group
            :style="{ width: inputWidth + 'px' }"
            v-if="formData.props[name].type === 'radio'"
            v-model="formData.model[name]"
            v-bind="formData.props[name]"
            v-on="formData.methods[name]"
          >
            <el-radio
              v-for="option in formData.props[name].options"
              :key="option.value"
              :label="option.value"
              >{{ option.label }}</el-radio
            >
          </el-radio-group>
          <!-- radio-button -->
          <el-radio-group
            :style="{ width: inputWidth + 'px' }"
            v-if="formData.props[name].type === 'radio-button'"
            v-model="formData.model[name]"
            v-bind="formData.props[name]"
            v-on="formData.methods[name]"
          >
            <el-radio-button
              v-for="option in formData.props[name].options"
              :key="option.value"
              :label="option.value"
              >{{ option.label }}</el-radio-button
            >
          </el-radio-group>
          <!-- checkbox -->
          <el-checkbox-group
            :style="{ width: inputWidth + 'px' }"
            v-if="formData.props[name].type === 'checkbox'"
            v-model="formData.model[name]"
            v-bind="formData.props[name]"
            v-on="formData.methods[name]"
          >
            <el-checkbox
              v-for="option in formData.props[name].options"
              :key="option.value"
              :label="option.value"
              :disabled="option.disabled || false"
              >{{ option.label }}</el-checkbox
            >
          </el-checkbox-group>
          <!-- cascader -->
          <el-cascader
            :style="{ width: inputWidth + 'px' }"
            v-if="formData.props[name].type === 'cascader'"
            v-model="formData.model[name]"
            v-bind="formData.props[name]"
            v-on="formData.methods[name]"
            class="w-100"
          ></el-cascader>

          <!-- 自定义form拓展 -->
          <slot
            v-if="formData.props[name].type === 'custom'"
            :name="name"
          ></slot>
        </el-form-item>
      </template>

      <div class="right">
        <div class="button">
          <span class="my-collapse" @click="showSearchAll = !showSearchAll">
            <i
              :class="[
                showSearchAll ? 'el-icon-arrow-up' : 'el-icon-arrow-down'
              ]"
            ></i>
            <span>{{ showSearchAll ? "收起" : "展开" }}</span>
          </span>
          <el-button type="primary" :size="size" @click="validateForm"
            >搜索</el-button
          >
          <el-button :size="size" @click="resetForm" style="margin-right: 10px"
            >重置</el-button
          >
        </div>
      </div>
    </el-form>
  </div>
</template>

<script>
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
export default {
  name: "el-search-query",
  components: {
    Treeselect
  },
  props: {
    formProps: {
      type: Object,
      default: () => ({})
    },
    inputWidth: {
      type: Number,
      default: 300
    }
  },
  data() {
    return {
      formData: {
        model: {},
        rules: {},
        props: {},
        methods: {}
      },

      dateMap: [
        "year",
        "month",
        "date",
        "dates",
        "week",
        "datetime",
        "datetimerange",
        "daterange",
        "monthrange"
      ],

      screenWidth: document.documentElement.clientWidth, //屏幕宽度
      columnNum: 2,
      size: "small",
      //存放外面传进来的on-progress的函数
      changeNumberFun: undefined,
      inputNumberFun: undefined,
      showSearchAll: false
    };
  },
  watch: {
    formProps: {
      handler(val, oldVal) {
        //这里是因为assign只能做到浅拷贝
        const isEmptyModel = !Object.keys(this.formData.model).length;
        if (isEmptyModel) {
          this.formData = Object.assign({}, this.formData, val);
        } else {
          // 合并custom插槽表单与组件内表单的model
          const customObj = {};
          Object.entries(this.formData.props).forEach(([key, value]) => {
            if (value.type === "custom") {
              customObj[key] = val.model[key];
            }
          });
          this.formData.model = Object.assign(
            {},
            this.formData.model,
            customObj
          );
        }
        //拷贝一份外面传进来的方法
        for (const key in this.formData.props) {
          if (this.formData.methods[key]) {
            if (
              this.formData.props[key].type === "number" &&
              this.formData.methods[key].change
            ) {
              this.changeNumberFun = this.formData.methods[key].change;
              this.$delete(this.formData.methods[key], "change");
            }
            if (
              this.formData.props[key].type === "number" &&
              this.formData.methods[key].input
            ) {
              this.inputNumberFun = this.formData.methods[key].input;
              this.$delete(this.formData.methods[key], "input");
            }
          }
        }
      },
      deep: true,
      immediate: true
    },
    screenWidth: function(val) {
      const oIframe = document.getElementById("divId");
      const item = document.querySelector(".item");
      console.log(oIframe.offsetWidth, item.offsetWidth, "宽度");
      console.log((oIframe.offsetWidth - 202) / (item.offsetWidth + 10));
      this.columnNum =
        Math.floor((oIframe.offsetWidth - 202) / (item.offsetWidth + 10)) - 1;
      if (this.columnNum < 1) {
        this.columnNum = 0;
      }
    }
  },
  computed: {
    classSize() {
      if (this.size == "medium") {
        return "treeselectMainMedium";
      } else if (this.size == "mini") {
        return "treeselectMainMini";
      } else {
        return "treeselectMainSmall";
      }
    }
  },
  mounted() {
    const _this = this;
    window.onresize = function() {
      // 定义窗口大小变更通知事件
      _this.screenWidth = document.documentElement.clientWidth; //窗口宽度
    };
  },

  beforeDestroy() {
    this.resetForm();
  },
  methods: {
    // 合并事件input
    mergeInputNumberFun(name, value, precision) {
      this.formatNumber(name, value, precision);
      if (typeof this.inputNumberFun === "function") {
        this.inputNumberFun(value);
      }
    },
    //合并事件change
    mergeChangeNumberFun(name, value) {
      this.handleNumberChange(name, value);
      if (typeof this.changeNumberFun === "function") {
        this.changeNumberFun(value);
      }
    },

    //获取formProps所需要的model
    getFormProp(formData) {
      const newProp = Object.assign(
        {},
        { labelWidth: "100px", inline: true },
        formData
      );
      Reflect.deleteProperty(newProp, "props");
      Reflect.deleteProperty(newProp, "methods");

      if (newProp.size) {
        this.size = newProp.size;
      } else {
        this.size = "small";
      }
      return newProp;
    },
    getItemProps(name) {
      const itemProp = Object.assign({}, this.formData.props[name]);
      if (itemProp.type === "number") {
        itemProp.type = "text";
      }
      if (itemProp.type === "int") {
        itemProp.type = "number";
      }
      return itemProp;
    },
    formatNumber(name, value, precision = 0) {
      const isMinus = value.charAt(0) === "-";
      const numberValue = value
        .replace(/[^\d.]/g, "")
        .replace(new RegExp(`\\.{${precision},}`, "g"), ".")
        .replace(".", "$#$")
        .replace(/\./g, "")
        .replace("$#$", ".")
        .replace(new RegExp(`^(-)*(\\d+)\\.(\\d{${precision},}).*$`), "$1$2.$3")
        .replace(/^\./g, "");
      const minusMap = { true: "-", false: "" };
      const floatValue = parseFloat(minusMap[isMinus] + numberValue);
      if (isNaN(floatValue)) {
        this.formData.model[name] = "";
        return;
      }
      const splitArray = numberValue.split(".");
      let strNumber = minusMap[isMinus] + numberValue;
      if (splitArray.length > 1) {
        const fixedStr = precision
          ? splitArray[1].substring(0, precision)
          : splitArray[1];
        if (splitArray.length > precision) {
          strNumber = minusMap[isMinus] + splitArray[0] + "." + fixedStr;
        } else {
          fixedStr &&
            (strNumber = minusMap[isMinus] + splitArray[0] + "." + fixedStr);
        }
      } else {
        strNumber = minusMap[isMinus] + numberValue;
      }
      this.formData.model[name] = strNumber;
    },
    handleNumberChange(name, value) {
      this.formData.model[name] = isNaN(parseFloat(value))
        ? 0
        : parseFloat(value);
    },
    isDateType(type) {
      return this.dateMap.indexOf(type) >= 0;
    },

    // 重置
    resetForm() {
      this.$refs["xmform"] && this.$refs["xmform"].resetFields();
      this.$emit("resetSearch", this.formData.model);
    },
    // form验证
    validateForm() {
      this.$refs["xmform"].validate(valid => {
        if (valid) {
          this.$emit("getSearchData", this.formData.model);
        } else {
          console.log("error submit!!");
          return false;
        }
      });
    },
    //手动获取form表单数据
    getFormData() {
      return this.formData.model;
    }
  }
};
</script>

<style lang="scss" scoped>
@mixin treeselect-main($size) {
  @if $size== "medium" {
    height: 36px;
    line-height: 20px;
    .vue-treeselect__control {
      height: 36px;
    }
    .vue-treeselect__option {
      padding-top: 4px;
      padding-bottom: 4px;
    }
  } @else if $size== "mini" {
    height: 28px;
    line-height: 15px;
    .vue-treeselect__control {
      height: 28px;
    }
    .vue-treeselect__option {
      padding-top: 3px;
      padding-bottom: 3px;
    }
    .vue-treeselect__placeholder {
      font-size: 12px;
      // padding-bottom: 10px;
    }
  } @else {
    height: 32px;
    line-height: 15px;
    .vue-treeselect__control {
      height: 32px;
    }
    .vue-treeselect__option {
      padding-top: 3px;
      padding-bottom: 3px;
    }
  }
}
/* Treeselect */
::v-deep .treeselectMainMini {
  @include treeselect-main("mini");
}
/* Treeselect */
::v-deep .treeselectMainMedium {
  @include treeselect-main("medium");
}
/* Treeselect */
::v-deep .treeselectMainSmall {
  @include treeselect-main("small");
}
::v-deep .el-radio-group label.el-radio {
  line-height: 2.4 !important;
}
::v-deep .el-range-separator {
  width: auto !important;
}
.w-100 {
  width: 100%;
}
.d-flex-row {
  display: flex;
  flex-direction: row;
}
::v-deep .el-upload__tip {
  margin-top: 0;
}
::v-deep .el-input-group {
  display: flex;
  .el-input-group__append,
  .el-input-group__prepend {
    width: auto;
    display: flex;
    align-items: center;
    > * {
      margin-top: 0;
    }
  }
}
::v-deep .el-upload-list__item .el-progress__text {
  display: none;
}
.layout {
  display: flex;
  justify-content: space-between;
}
.right {
  justify-content: flex-end;
  // flex-grow: 1;
}
.button {
  display: flex;
  align-items: center;
  justify-content: flex-end;
}
.my-collapse {
  width: 70px;
  cursor: pointer;
  color: #409eff;
  font-size: 12px;

  padding-right: 20px;
  span {
    padding-left: 4px;
  }
}
.item:last-child {
  flex-grow: 1;
}
.form-item {
  display: flex;
  justify-content: space-between;
  align-content: space-between;
  flex-wrap: wrap;
  // justify-content: flex-start;

  width: 100%;
}
</style>
